package com.springboot.codeminestarter.codemine.aop.db;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.mchange.v2.c3p0.DriverManagerDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Configuration
public class DataSourceHolder implements ApplicationContextAware {
    private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceHolder.class);
    private static final String DATASOURCE_CONFIG_NAME = "datasource.properties";
    private static final String DB_GLOBAL_CONFIG = "db.global.config";
    private static final String DB_GLOBAL_DEFAULT = "db.global.default";

    private static ApplicationContext applicationContext;

    @Bean
    public DataSource dataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> driverManagerDataSourceMap = loadDBProperties();
        Object defaultConfig = driverManagerDataSourceMap.get(DB_GLOBAL_DEFAULT);
        dynamicDataSource.setDefaultTargetDataSource(driverManagerDataSourceMap.get(defaultConfig));
        driverManagerDataSourceMap.remove(DB_GLOBAL_DEFAULT);
        dynamicDataSource.setTargetDataSources(driverManagerDataSourceMap);
        dynamicDataSource.afterPropertiesSet();
        return dynamicDataSource;
    }

//    @Bean
//    public DataSource primaryDataSource() {
//        // 创建并配置主数据源
//        DriverManagerDataSource driverManager = loadDBProperties().get("master");
//        LOGGER.info("{}，已注册数据源：{}", driverManager.getJdbcUrl(), driverManager.toString());
//        return driverManager;
//    }
//
//    @Bean
//    public DataSource secondaryDataSource() {
//        // 创建并配置第二数据源
//        DriverManagerDataSource driverManager = loadDBProperties().get("import");
//        LOGGER.info("{}，已注册数据源：{}", driverManager.getJdbcUrl(), driverManager.toString());
//        return driverManager;
//    }
//
//    @Bean
//    public DataSource oracleDataSource() {
//        // 创建Oracle数据源
//        DriverManagerDataSource driverManager = loadDBProperties().get("oracle");
//        LOGGER.info("{}，已注册数据源：{}", driverManager.getJdbcUrl(), driverManager.toString());
//        return driverManager;
//    }

    private DataSource register(String beanName, DriverManagerDataSource driverManagerDataSource) {
        DefaultListableBeanFactory factory = (DefaultListableBeanFactory)applicationContext.getAutowireCapableBeanFactory();
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition("com.mchange.v2.c3p0.DriverManagerDataSource");
        builder.addPropertyValue("driverClass", driverManagerDataSource.getDriverClass());
        builder.addPropertyValue("jdbcUrl", driverManagerDataSource.getJdbcUrl());
        builder.addPropertyValue("user", driverManagerDataSource.getUser());
        builder.addPropertyValue("password", driverManagerDataSource.getPassword());
        factory.registerBeanDefinition(beanName, builder.getBeanDefinition());
        LOGGER.info("{}，已注册数据源：{}", driverManagerDataSource.getJdbcUrl(), driverManagerDataSource.toString());
        return applicationContext.getBean(beanName, DataSource.class);
    }

    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        // 使用默认的sqlSessionFactory
        /*SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        // 其他配置如配置mapper文件等
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:dao/*.xml"));*/

        // 使用mybatis plus
        MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:dao/*.xml"));
        return sqlSessionFactoryBean.getObject();
    }

    private Map<Object, Object> loadDBProperties() {
        //  2024/8/20 14:22
        Properties properties = new Properties();
        Map<Object, Object> driverManagerMap = new HashMap<>(3);
        InputStreamReader reader = null;
        InputStream inputStream = DataSourceHolder.class.getClassLoader().getResourceAsStream(DATASOURCE_CONFIG_NAME);
        try {
            reader = new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8);
            properties.load(reader);
            String globalConfig = properties.getProperty(DB_GLOBAL_CONFIG);
            String defaultConfig = properties.getProperty(DB_GLOBAL_DEFAULT);
            if (StringUtils.hasLength(globalConfig)) {
                String[] dbs = globalConfig.split(",");
                // 注册数据源
                LOGGER.info("数据源：{}", Arrays.toString(dbs));
                for (String dbType : dbs) {
                    DataSource dataSource = registerDriverManager(properties, dbType);
                    LOGGER.info("注册数据源：{}", dbType);
                    driverManagerMap.put(dbType, dataSource);
                }
            } else {
                DataSource dataSource = registerDriverManager(properties, defaultConfig);
                LOGGER.info("注册默认数据源：{}", defaultConfig);
                driverManagerMap.put(defaultConfig, dataSource);
            }
            driverManagerMap.put(DB_GLOBAL_DEFAULT, defaultConfig);
        } catch (IOException e) {
            LOGGER.error("注册数据源失败: {}", e);
            e.printStackTrace();
        }  finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return driverManagerMap;
    }

    private DataSource registerDriverManager(Properties properties, String dbType) {
        DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
        driverManagerDataSource.setDriverClass(properties.getProperty("db." + dbType + ".driverClassName"));
        driverManagerDataSource.setJdbcUrl(properties.getProperty("db." + dbType + ".jdbcUrl"));
        driverManagerDataSource.setUser(properties.getProperty("db." + dbType + ".username"));
        driverManagerDataSource.setPassword(properties.getProperty("db." + dbType + ".password"));
        DataSource dataSource = register(dbType, driverManagerDataSource);
        return dataSource;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {

        DataSourceHolder.applicationContext = applicationContext;
    }
}
